﻿using Core.DataAccess.Model;
using Core.DataAccess.Model.Project.Queue;
using Core.Framework.Model.Common;
using Core.Framework.Model.WebSockets;
using Core.Framework.Util;
using Core.IBusiness.ISocketModule;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Core.Framework.EntityExtend;

namespace Core.Business.SocketModule
{
    public class SocketMessage : ISocketMessage
    {

        public List<SocketBackupsMessage> GetBackupsMessages(string projectToken, Pagination pagination)
        {
            return this.GetBackupsMessagesByWhere(a => a.ProjectToken == projectToken, pagination);
        }

        public List<SocketBackupsMessage> GetBackupsMessagesByMsgKey(string msgKey, string projectToken,
            Pagination pagination)
        {
            return this.GetBackupsMessagesByWhere(a => a.ProjectToken == projectToken && a.MsgKey == msgKey,
                pagination);
        }

        public List<SocketBackupsMessage> GetBackupsMessagesByMsgKeyAndTemplate(string msgKey, string template,
            string projectToken, Pagination pagination)
        {
            return this.GetBackupsMessagesByWhere(
                a => a.ProjectToken == projectToken && a.Template == template && a.MsgKey == msgKey, pagination);
        }

        public List<SocketGroupMessage> GetGroupMessages(string projectToken, Pagination pagination)
        {
            return this.GetGroupMessagesByWhere(a => a.ProjectToken == projectToken, pagination);
        }

        public List<SocketGroupMessage> GetGroupMessagesByMsgKey(string msgKey, string projectToken,
            Pagination pagination)
        {
            return this.GetGroupMessagesByWhere(a => a.ProjectToken == projectToken && a.MsgKey == msgKey, pagination);
        }

        public List<SocketGroupMessage> GetGroupMessagesByMsgKeyAndTemplate(string msgKey, string template,
            string projectToken, Pagination pagination)
        {
            return this.GetGroupMessagesByWhere(
                a => a.ProjectToken == projectToken && a.Template == template && a.MsgKey == msgKey, pagination);
        }

        public List<SocketOfflineMessage> GetOfflineMessages(string projectToken, Pagination pagination)
        {
            return this.GetOfflineMessagesByWhere(a => a.ProjectToken == projectToken, pagination);
        }

        public List<SocketOfflineMessage> GetOfflineMessagesByMsgKey(string msgKey, string projectToken,
            Pagination pagination)
        {
            return this.GetOfflineMessagesByWhere(a => a.ProjectToken == projectToken && a.MsgKey == msgKey,
                pagination);
        }

        public List<SocketOfflineMessage> GetOfflineMessagesByMsgKeyAndTemplate(string[] msgKeys, string template,
            string projectToken, Pagination pagination)
        {
            return this.GetOfflineMessagesByWhere(
                a => a.ProjectToken == projectToken && a.Template == template && msgKeys.Contains(a.MsgKey), pagination,
                true);
        }

        /// <summary>
        /// 历史消息
        /// </summary>
        /// <param name="values"></param>
        public void SaveHistory(RedisValue[] values)
        {
            if (null != values)
                using (var context = new ProjectSocketContext())
                {
                    List<SocketBackupsMessage> backups = new List<SocketBackupsMessage>();

                    foreach (var item in values)
                    {
                        SocketBackupsMessage entity
                            = this.StructureSocketBackupsMessage((string) item);

                        if (null != entity)
                            backups.Add(entity);
                    }

                    context.SocketBackupsMessage.BulkInsert(backups);
                    context.BeginSaveChanges();

                    context.SaveChanges();
                }
        }

        /// <summary>
        /// 单一订阅用户离线消息
        /// </summary>
        /// <param name="values"></param>
        public void SaveSingleOffLine(RedisValue[] values)
        {

            if (null != values)
                using (var context = new ProjectSocketContext())
                {
                    List<SocketOfflineMessage> offlines = new List<SocketOfflineMessage>();

                    foreach (var item in values)
                    {
                        SocketOfflineMessage entity
                            = this.StructureSocketOfflineMessage((string) item);

                        if (null != entity)
                            offlines.Add(entity);
                    }

                    context.SocketOfflineMessage.BulkInsert(offlines);
                    context.BeginSaveChanges();
                }
        }

        #region helper

        private SocketBackupsMessage StructureSocketBackupsMessage(string value)
        {
            var model = value.TryToEntity<MessageQueue>();

            return new SocketBackupsMessage
            {
                ProjectToken = model.ClientInfo.Project.ProjectToken,
                MsgContext = this.StructureParameter(model),
                MsgKey = model.Message.Channel,
                Template = model.Template.ToLower(),
                SendTime = model.Message.SendDateTime
            };
        }

        private SocketOfflineMessage StructureSocketOfflineMessage(string value)
        {
            var model = value.TryToEntity<MessageQueue>();

            return new SocketOfflineMessage
            {
                ProjectToken = model.ClientInfo.Project.ProjectToken,
                MsgContext = this.StructureParameter(model),
                MsgKey = model.Message.Channel,
                Template = model.Template.ToLower(),
                SendTime = model.Message.SendDateTime
            };
        }

        /// <summary>
        /// 构造发送消息内容
        /// </summary>
        /// <returns></returns>
        public string StructureParameter(MessageQueue messageQueue)
        {
            return new
            {
                message = messageQueue.Message.Content,
                messageParameter = messageQueue.Message.Parameter,

                userKey = messageQueue.ClientInfo.User.Key,
                userParameter = messageQueue.ClientInfo.User.Parameter,
                sendDateTime = messageQueue.Message.SendDateTime,
                template = messageQueue.Template.ToLower(),

                messageType = messageQueue.Message.MessageType.ToString(),
                type = "current"

            }.TryToJson();
        }

        private List<SocketBackupsMessage> GetBackupsMessagesByWhere(
            Expression<Func<SocketBackupsMessage, bool>> where,
            Pagination pagination, bool delete = false)
        {
            using (var context = new ProjectSocketContext())
            {

                pagination.records
                    = context.SocketBackupsMessage.Where(where).Count();

                var data = context
                    .SocketBackupsMessage
                    .Where(where)
                    .OrderByDescending(a => a.Id)
                    .Skip(pagination.rows * (pagination.page - 1))
                    .Take(pagination.rows)
                    .ToList();

                if (delete)
                {
                    foreach (var item in data)
                        context.SocketBackupsMessage.Remove(item);

                    context.SaveChanges();
                }


                return data;

            }

            ;
        }

        private List<SocketOfflineMessage> GetOfflineMessagesByWhere(
            Expression<Func<SocketOfflineMessage, bool>> where,
            Pagination pagination, bool delete = false)
        {
            using (var context = new ProjectSocketContext())
            {
                pagination.records
                    = context.SocketOfflineMessage.Where(where).Count();

                if (pagination.records < (pagination.rows * (pagination.page - 1) + 1))
                    return new List<SocketOfflineMessage>();
                var data = context
                    .SocketOfflineMessage
                    .Where(where)
                    .OrderByDescending(a => a.Id)
                    .Skip(pagination.rows * (pagination.page - 1))
                    .Take(pagination.rows)
                    .ToList();

                if (delete)
                {
                    foreach (var item in data)
                        context.SocketOfflineMessage.Remove(item);

                    context.SaveChanges();
                }


                return data;

            }

            ;
        }

        private List<SocketGroupMessage> GetGroupMessagesByWhere(
            Expression<Func<SocketGroupMessage, bool>> where,
            Pagination pagination, bool delete = false)
        {
            using (var context = new ProjectSocketContext())
            {

                pagination.records
                    = context.SocketGroupMessage.Where(where).Count();

                var data = context
                    .SocketGroupMessage
                    .Where(where)
                    .OrderByDescending(a => a.Id)
                    .Skip(pagination.rows * (pagination.page - 1))
                    .Take(pagination.rows)
                    .ToList();

                if (delete)
                {
                    foreach (var item in data)
                        context.SocketGroupMessage.Remove(item);

                    context.SaveChanges();
                }


                return data;

            }

            ;
        }

        #endregion

    }
}
